#ifndef __NA__
#define __NA__
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>


#endif
union semun {
	int              val;    /* Value for SETVAL */
	struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short  *array;  /* Array for GETALL, SETALL */
	struct seminfo  *__buf;  /* Buffer for IPC_INFO
								(Linux-specific) */
};

int main()
{
	//获取键值
	key_t key=ftok("/",'2');
	if(key==-1){perror("获取键值失败");return -1;}
	//创建信号量集
	int sem_id=semget(key,3,IPC_CREAT|IPC_EXCL|0664);
	if(sem_id==-1&&errno==EEXIST)//已经存在
	{
		perror("创建失败：信号量集已存在");
		sem_id=semget(key,3,IPC_CREAT);
		if(sem_id==-1){perror("打开信号量集失败");return -1;}
		printf("打开信号量集成功：%d\n",sem_id);
	}
	else
	{
		printf("打开信号量集成功：%d\n",sem_id);
	}
	perror("打开信号量级");
	//准备控制共用体初始化信号量集
	union semun buf;
	buf.val=1;
	if(semctl(sem_id,0,SETVAL,buf,NULL)==-1){perror("初始化0失败");return -1;}
	buf.val=0;
	if(semctl(sem_id,1,SETVAL,buf,NULL)==-1){perror("初始化1失败");return -1;}
	if(semctl(sem_id,2,SETVAL,buf,NULL)==-1){perror("初始化2失败");return -1;}
	buf.val=semctl(sem_id,0,GETVAL);printf("信号量[0]=%d\n",buf.val);
	buf.val=semctl(sem_id,1,GETVAL);printf("信号量[1]=%d\n",buf.val);
	buf.val=semctl(sem_id,2,GETVAL);printf("信号量[2]=%d\n",buf.val);
	//定义控制结构体
	struct sembuf arr={0,0,0};
	////////////////////////////////////创建子进程////////////////////////////////////
	pid_t pid1=fork();
	if(pid1>0)
	{
		//父进程1
		int n=5;
		while(n--)
		{
			arr.sem_num=0;
			arr.sem_op=-1;
			if(semop(sem_id,&arr,1)==-1){perror("申请0号信号量失败");return -1;}
			printf("A\n");
			arr.sem_num=1;
			arr.sem_op=1;
			if(semop(sem_id,&arr,1)==-1){perror("释放1号信号量失败");return -1;}
		}
		//回收子进程
		wait(NULL);
	}
	else if(pid1==0)
	{
		pid_t pid2=fork();
		if(pid2>0)
		{
			//子进程1
			int n=5;
			while(n--)
			{
				arr.sem_num=1;
				arr.sem_op=-1;
				if(semop(sem_id,&arr,1)==-1){perror("申请1号信号量失败");return -1;}
				printf("B\n");
				arr.sem_num=2;
				arr.sem_op=1;
				if(semop(sem_id,&arr,1)==-1){perror("释放2号信号量失败");return -1;}
			}
			//回收子进程
			wait(NULL);
			//退出子进程
			exit(getppid());
		}
		else if(pid2==0)
		{
			//子进程2
			int n=5;
			while(n--)
			{
				arr.sem_num=2;
				arr.sem_op=-1;
				if(semop(sem_id,&arr,1)==-1){perror("申请2号信号量失败");return -1;}
				printf("C\n");
				arr.sem_num=0;
				arr.sem_op=1;
				if(semop(sem_id,&arr,1)==-1){perror("释放0号信号量失败");return -1;}
			}
			//退出子进程
			exit(getppid());
		}
		else
		{
			perror("创建子进程失败");
		}
	}
	else
	{
		perror("创建子进程失败");
	}
	//删除信号量集
	if(semctl(sem_id,0,IPC_RMID)==-1){perror("删除信号量集失败");return -1;}
	return 0;
}
